﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows.Forms;
using OPCAutomation;
using thinger.com.Models;
namespace thinger.com.MyFirstOPCDemo
{
    public enum ReadMethod
    {
        Sync,
        Async,
        Subscribe
    }
    public partial class FrmMain : Form
    {
        public FrmMain()
        {
            InitializeComponent();

            this.dataGridView1.AutoGenerateColumns = false;

            this.cmb_ReadMethod.DataSource = Enum.GetNames(typeof(ReadMethod));

            this.btn_Refresh_Click(null, null);
        }

        // OPC服务器
        private OPCServer KepServer;

        // 变量的集合
        private List<OPCDAVariable> OPCVarList = new List<OPCDAVariable>();

        // OPCGroups
        private OPCGroups KepGroups;

        // OPCGroup
        private OPCGroup KepGroup;

        // 领取方式
        private ReadMethod ReadMethod;

        // ServerHandles
        private Array ServerHandles;

        // Errors
        private Array Errors;

        private int TransactionID;

        private int CancelID;


        #region 刷新节点
        /// <summary>
        /// 刷新节点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Refresh_Click(object sender, EventArgs e)
        {
            // 清空
            this.cmb_ServerNode.Items.Clear();

            IPHostEntry IPHost = Dns.GetHostEntry(Environment.MachineName);

            if(IPHost.AddressList.Length>0)
            {
                for(int i=0;i<IPHost.AddressList.Length;i++)
                {
                    string host = Dns.GetHostEntry(IPHost.AddressList[i]).HostName;
                    if(!this.cmb_ServerNode.Items.Contains(host))
                    {
                        this.cmb_ServerNode.Items.Add(host);
                    }
                }
            }

        }
        #endregion

        #region  获取OPC服务列表
        /// <summary>
        /// 获取OPC服务列表
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmb_ServerNode_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(KepServer == null)
            {
                KepServer = new OPCServer();
            }
            object serviceList = KepServer.GetOPCServers(this.cmb_ServerNode.Text);
            
            foreach(var item in (Array)serviceList)
            {
                if(!this.cmb_ServerName.Items.Contains(item))
                {
                    this.cmb_ServerName.Items.Add(item);
                }
            }
        }
        #endregion

        #region 连接及断开连接
        private void btn_Connect_Click(object sender, EventArgs e)
        {
            if(this.btn_Connect.Text == "Connect")
            {
                // 连接服务器
                if(KepServer != null)
                {
                    KepServer = new OPCServer();
                }
                try
                {
                    KepServer.Connect(this.cmb_ServerName.Text, this.cmb_ServerNode.Text);
                } catch(Exception err)
                {
                    MessageBox.Show("连接失败：" + err.Message);
                    return;
                }

                OPCBrowser KepBrowser = this.KepServer.CreateBrowser();
                KepBrowser.ShowBranches();
                KepBrowser.ShowLeafs(true);
                this.lst_Items.Items.Clear();
                foreach(var item in KepBrowser)
                {
                    this.lst_Items.Items.Add(item);
                }

                // 通信组集合
                KepGroups = KepServer.OPCGroups;
                KepGroups.DefaultGroupDeadband = 0;
                KepGroups.DefaultGroupIsActive = true;

                KepGroup = KepGroups.Add("型格教育");
                KepGroup.IsActive = true;
                KepGroup.IsSubscribed = true;
                KepGroup.UpdateRate = 200;

                KepGroup.AsyncReadComplete += KepGroup_AsyncReadComplete;

                this.btn_Connect.Text = "DisConn";
            } 
            else
            {
                // 断开连接服务器
                KepServer.Disconnect();
                this.btn_Connect.Text = "Connect";
            }
        }


        #endregion

        #region 双击选择变量
        private void lst_Items_DoubleClick(object sender, EventArgs e)
        {
            if(this.lst_Items.SelectedItem != null)
            {
                this.OPCVarList.Add(new OPCDAVariable()
                {
                    OPCItemID = this.lst_Items.SelectedItem.ToString(),
                    ClientHandle = this.OPCVarList.Count
                });
                List<string> TempItemIDs = new List<string>();
                List<int> TempClientHandle = new List<int>();

                // 占位
                TempItemIDs.Add("");
                TempClientHandle.Add(0);

                for(int i=0;i<this.OPCVarList.Count;i++)
                {
                    TempItemIDs.Add(this.OPCVarList[i].OPCItemID);
                    TempClientHandle.Add(this.OPCVarList[i].ClientHandle);
                }

                Array ItemIDs = TempItemIDs.ToArray();
                Array ClientHandle = TempClientHandle.ToArray();

                // 添加变量
                KepGroup.OPCItems.AddItems(this.OPCVarList.Count, ItemIDs, ClientHandle,out ServerHandles,out Errors);
            }
        }
        #endregion


        #region 开始读取及停止读取
        private void btn_Read_Click(object sender, EventArgs e)
        {
            if(this.btn_Read.Text == "Start Read")
            {
                // ReadMethod = (ReadMethod)this.cmb_ReadMethod.SelectedIndex;
                ReadMethod = (ReadMethod)Enum.Parse(typeof(ReadMethod), this.cmb_ReadMethod.Text, true);

                switch (ReadMethod)
                {
                    case ReadMethod.Subscribe:
                        // 订阅方式
                        KepGroup.DataChange += KepGroup_DataChange;
                        break;
                    default:
                        this.updateTimer.Enabled = true;
                        break;
                }
                this.btn_Read.Text = "Stop Read";
            } 
            else
            {
                switch (ReadMethod)
                {
                    case ReadMethod.Subscribe:
                        // 取消订阅方式
                        KepGroup.DataChange -= KepGroup_DataChange;
                        break;
                    default:
                        this.updateTimer.Enabled = false;
                        break;
                }
                this.btn_Read.Text = "Start Read";
            }
           
        }

        #endregion


        private void updateTimer_Tick(object sender, EventArgs e)
        {
            // 不断读取
            if(this.OPCVarList.Count>0)
            {
                switch (ReadMethod) 
                {
                    case ReadMethod.Sync:
                        try
                        {
                            KepGroup.SyncRead(1, this.OPCVarList.Count, ref ServerHandles, out Array Values, out Errors, out object Qualities, out object TimeStamps);
                           
                            // 数据解析
                            for(int i=0;i<this.OPCVarList.Count;i++)
                            {
                                object value = Values.GetValue(i + 1);
                                if(value!=null)
                                {
                                    this.OPCVarList[i].OPCValue = value.ToString();
                                    this.OPCVarList[i].OPCDataType = value.GetType().ToString();
                                    this.OPCVarList[i].OPCQualitye = ((Array)Qualities).GetValue(i+1).ToString();
                                    this.OPCVarList[i].OPCUpdateTime = Convert.ToDateTime(((Array)TimeStamps).GetValue(i + 1)).ToString();
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show("同步读取出错"+ex.Message);
                            this.updateTimer.Enabled = false;
                            this.btn_Read.Text = "Stop Read";
                        }
                        this.dataGridView1.DataSource = null;
                        this.dataGridView1.DataSource = this.OPCVarList;
                        //this.dataGridView1.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
                        break;
                    case ReadMethod.Async:
                        try
                        {
                            KepGroup.AsyncRead(this.OPCVarList.Count, ServerHandles, out Errors, TransactionID, out CancelID);
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show("异步读取出错" + ex.Message);
                            this.updateTimer.Enabled = false;
                            this.btn_Read.Text = "Stop Read";
                        }
                        break;
                    case ReadMethod.Subscribe:
                        break;
                    default:
                        break;
                }
            }
        }

        /// <summary>
        /// 订阅方式数据发生变化触发的事件
        /// </summary>
        /// <param name="TransactionID"></param>
        /// <param name="NumItems"></param>
        /// <param name="ClientHandles"></param>
        /// <param name="ItemValues"></param>
        /// <param name="Qualities"></param>
        /// <param name="TimeStamps"></param>
        private void KepGroup_DataChange(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps)
        {
            for (int i = 1; i <= NumItems; i++)
            {
                object value = ItemValues.GetValue(i);
                if (value != null)
                {
                    int clientHandle = Convert.ToInt32(ClientHandles.GetValue(i));
                    var query = this.OPCVarList.Where(o => o.ClientHandle == clientHandle).FirstOrDefault();
                    if (query != null)
                    {
                        query.OPCValue = value.ToString();
                        query.OPCDataType = value.GetType().ToString();
                        query.OPCQualitye = Qualities.GetValue(i).ToString();
                        query.OPCUpdateTime = Convert.ToDateTime((TimeStamps).GetValue(i)).ToString();
                    }
                }
            }
            this.dataGridView1.DataSource = null;
            this.dataGridView1.DataSource = this.OPCVarList;

        }

        private void KepGroup_AsyncReadComplete(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps, ref Array Errors)
        {
            for (int i = 1; i <= NumItems; i++)
            {
                object value = ItemValues.GetValue(i);
                if(value!=null)
                {
                    int clientHandle = Convert.ToInt32(ClientHandles.GetValue(i));
                    var query = this.OPCVarList.Where(o => o.ClientHandle == clientHandle).FirstOrDefault();
                    if(query!=null)
                    {
                        query.OPCValue = value.ToString();
                        query.OPCDataType = value.GetType().ToString();
                        query.OPCQualitye = Qualities.GetValue(i).ToString();
                        query.OPCUpdateTime = Convert.ToDateTime((TimeStamps).GetValue(i)).ToString();
                    }
                }
            }
            this.dataGridView1.DataSource = null;
            this.dataGridView1.DataSource = this.OPCVarList;
        }

        private void dataGridView1_CellContentDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if(this.dataGridView1.SelectedRows!=null)
            {
                int index = this.dataGridView1.CurrentRow.Index;

                FrmParamSet objFrm = new FrmParamSet(this.OPCVarList[index]);

                DialogResult dr = objFrm.ShowDialog();

                if(dr==DialogResult.OK)
                {
                    string setValue = objFrm.SetValue;
                    bool isSync = objFrm.IsSync;

                    // 写入
                    List<int> tempServerHandler = new List<int>();
                    List<object> tempSetValues = new List<object>();
                    
                    tempServerHandler.Add(0);
                    tempSetValues.Add("");

                    tempServerHandler.Add(Convert.ToInt32(ServerHandles.GetValue(index + 1)));
                    tempSetValues.Add(setValue);

                    Array ServerHandle = tempServerHandler.ToArray();
                    Array SetValues = tempSetValues.ToArray();
                    if(isSync)
                    {
                        try
                        {
                            KepGroup.SyncWrite(1, ref ServerHandle, ref SetValues, out Errors);
                        }
                        catch (Exception)
                        {
                            return;
                        }
                        
                    }
                    else
                    {
                        try
                        {
                            KepGroup.AsyncWrite(1, ref ServerHandle, ref SetValues, out Errors,TransactionID,out CancelID);
                        }
                        catch (Exception)
                        {
                            return;
                        }
                    }
                }
            }
        }
    }
}
